home *** CD-ROM | disk | FTP | other *** search
- /*
- * $RCSfile: restart.C,v $
- * $Revision: 1.1.1.1 $
- * $Date: 1996/05/04 21:55:55 $
- */
- /**********************************************************************
- * EXODUS Database Toolkit Software
- * Copyright (c) 1991 Computer Sciences Department, University of
- * Wisconsin -- Madison
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY OF WISCONSIN --
- * MADISON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
- * THE DEPARTMENT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
- * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * The EXODUS Project Group requests users of this software to return
- * any improvements or extensions that they make to:
- *
- * EXODUS Project Group
- * c/o David J. DeWitt and Michael J. Carey
- * Computer Sciences Department
- * University of Wisconsin -- Madison
- * Madison, WI 53706
- *
- * or exodus@cs.wisc.edu
- *
- * In addition, the EXODUS Project Group requests that users grant the
- * Computer Sciences Department rights to redistribute these changes.
- **********************************************************************/
-
- #include "sysdefs.h"
- #include "ess.h"
- #include "checking.h"
- #include "trace.h"
- #include "error.h"
- #include "list.h"
- #include "pool.h"
- #include "tid.h"
- #include "io.h"
- #include "lock.h"
- #include "object.h"
- #include "msgdefs.h"
- #include "thread.h"
- #include "semaphore.h"
- #include "latch.h"
- #include "link.h"
- #include "lsn.h"
- #include "bf.h"
- #include "volume.h"
- #include "openlog.h"
- #include "trans.h"
- #include "log.h"
- #include "logrecs.h"
- #include "threadstate.h"
- #include "adminmsg.h"
- #include "util_funcs.h"
- #include "log_intfuncs.h"
- #include "log_extfuncs.h"
- #include "recover_intfuncs.h"
- #include "trans_extfuncs.h"
- #include "bf_extfuncs.h"
- #include "io_extfuncs.h"
- #include "thread_funcs.h"
- #include "admin_funcs.h"
- #include "thread_globals.h"
- #include "log_globals.h"
- #include "processStats.h"
- #include "distr.h"
- #include "distr_extfuncs.h"
-
- extern FILE *sm_ErrorStream;
-
-
- void
- restart (
-
- OPENLOG *openLog
- )
- {
-
- register LOGRECORDHDR *record;
- register FOUR offset;
- register LOGPAGEHDR *pageHeader;
- register LOGPAGEHDR *endHeader;
- register GROUPLINK *groupLink;
- CHECKPOINTMASTER *checkMaster;
- LSNOFFSET checkpointLSN;
- LSNOFFSET oldestLSN;
- LSNOFFSET lastLSN;
- DIRTYPAGEINFO *oldestPage;
- TRANSREC *oldestTrans;
- PID pid;
- ProcessStats phaseTime;
- ProcessStats recoveryTime;
- GROUPLINK *logRecordBuffer = NULL;
- #ifdef DEBUG
- LSN debugLSN;
- #endif DEBUG
-
- TRACE(TR_LOG|TR_RECOVER, TR_LEVEL_1);
-
- CheckpointsEnabled = FALSE; // do not allow checkpoints
-
- recoveryTime.Start();
-
- /*
- * fill in the volume id
- */
- pid.volid = openLog->volid;
-
- /*
- * get a pointer to the checkpoint info
- */
- checkMaster = (CHECKPOINTMASTER *) openLog->controlBuffer->bufFrame;
-
- /*
- * get the lsn of the most recent checkpoint record
- */
- checkpointLSN = checkMaster->checkRecordLSN.offset;
- LastFlushedCheckpoint = checkMaster->checkRecordLSN;
- OldestDirtyPageLSN = LastFlushedCheckpoint;
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("checkpointLSN:%d", checkpointLSN));
-
- /*
- * calculate the page the checkpoint record LSN is on
- */
- pid.page = LSN_TO_BLOCK(checkpointLSN, openLog);
- TRPRINT(TR_RECOVER|TR_LOG, TR_LEVEL_2, ("log page:%d", pid.page - openLog->logFileAddr));
-
- /*
- * read in the checkpoint record log page
- */
- if ((groupLink = bf_ReadPage(openLog->readGroup, &pid,
- openLog->page2size, NOFLAGS)) == NULL) {
- fprintf(sm_ErrorStream, "SERVER ERROR: log volume may need to be regenerated if this is the\n");
- fprintf(sm_ErrorStream, " first time it has been used since being formatted.\n");
- admin_ShutServer(SHUT_ABNORMAL_EXIT);
- }
-
- /*
- * get a pointer to the page header and tailers
- */
- pageHeader = (LOGPAGEHDR *) groupLink->bufFrame;
- endHeader = (LOGPAGEHDR *) (((char *) pageHeader) + openLog->lastUsableByte);
-
- /*
- * check the page numbers
- */
- SM_ASSERT(LEVEL_1, pageHeader->pageNumber == LSN_TO_LOG_PAGE(checkpointLSN, openLog));
- SM_ASSERT(LEVEL_1, endHeader->pageNumber == LSN_TO_LOG_PAGE(checkpointLSN, openLog));
-
- /*
- * check to make sure the magic is ok
- * this is fatal since all sectors have a valid magic
- */
- if (CHECK_LOGPAGE_MAGIC(pageHeader) || CHECK_LOGPAGE_MAGIC(endHeader)) {
-
- SM_ERROR(TYPE_FATAL, esmBADLOGPAGEHEADER);
- }
-
- /*
- * calculate the offset of the checkpoint record
- */
- offset = LOG_PAGE_OFFSET(checkpointLSN, openLog);
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_2, ("oldest page offset:%d", offset));
-
- /*
- * check to make sure that the lastRecord field is consistent
- */
- if (endHeader->lastRecord < offset) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * get a pointer to the record header
- */
- record = (LOGRECORDHDR *) (groupLink->bufFrame + offset);
-
- /*
- * check to see if the record resides on a page
- */
- if ((openLog->lastUsableByte - offset) < record->length) {
-
- logRecordBuffer = getLogRecordBuffer(record->length);
- SM_ASSERT(LEVEL_3, logRecordBuffer != NULL);
-
- /*
- * combine the record
- */
- if (combineRecord(openLog, record, (openLog->lastUsableByte - offset), FALSE, logRecordBuffer) != esmNOERROR) {
-
- /*
- * Reached end of log
- */
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * get a pointer to the record header
- */
- record = (LOGRECORDHDR *) logRecordBuffer->bufFrame;
- }
-
- /*
- * check to make sure the magic matches
- */
- if (CHECK_LOGRECORD_MAGIC(record)) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /*
- * initialize the dirty page table
- */
- clearDirtyPageTable();
-
- /*
- * Unfix the checkpoint log record page
- */
- bf_UnfixPage(groupLink, BF_DEFAULT, FALSE);
-
- /*
- * do the analysis phase
- */
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning ANALYSIS"));
- phaseTime.Start();
- lastLSN = processLogForward(openLog, checkpointLSN, ANALYSIS_PHASE);
- phaseTime.Stop();
- fprintf(sm_ErrorStream, "Recovery Statistics:\n");
- phaseTime.PrintStatsHeader(sm_ErrorStream);
- phaseTime.PrintStats(sm_ErrorStream, "AnlysPass");
-
- /*
- * Determine the oldest LSN in the dirty page table
- * and the oldest firstLSN for any transaction which is
- * prepared or committed but not ended
- * Use this to determine where to begin redo
- */
- oldestPage = findOldestDirtyPage();
- oldestTrans = findOldestTrans();
-
- if ((oldestPage == NULL) && (oldestTrans == NULL)) {
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("both NULL"));
- oldestLSN = checkpointLSN;
- }
- else if (oldestPage == NULL) {
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestPage NULL"));
- oldestLSN = oldestTrans->prepareLSN.offset;
- }
- else if (oldestTrans == NULL) {
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestTrans NULL"));
- oldestLSN = oldestPage->lsn.offset;
- }
- else {
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("neither NULL"));
- if (compareLSN(&(oldestTrans->prepareLSN), &(oldestPage->lsn)) < 0)
- oldestLSN = oldestTrans->prepareLSN.offset;
- else
- oldestLSN = oldestPage->lsn.offset;
- }
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("oldestLSN:%d",oldestLSN));
- /*
- * Remember the last record in the log so that volumes can
- * be mounted properly
- */
- openLog->nextValidLSN.offset = lastLSN;
- openLog->nextValidLSN.wrapCount = openLog->wrapCount;
-
- /*
- * Mount all necessary volumes
- */
- if (mountRecoveryVolumes() != esmNOERROR) {
- fprintf(sm_ErrorStream,
- "Cannot mount volumes needed for recovery!\n");
- admin_ShutServer(SHUT_ABNORMAL_EXIT);
- }
-
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning REDO"));
- phaseTime.Start();
- lastLSN = processLogForward(openLog, oldestLSN, REDO_PHASE);
- phaseTime.Stop();
- phaseTime.PrintStats(sm_ErrorStream, "RedoPass");
-
- #ifdef DEBUG
-
- /*
- * Since redo brings the system to a consistent state,
- * make sure all the volumes' bitmaps are in order
- */
- if (io_CheckAllVolumes() != esmNOERROR) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- #endif DEBUG
-
- /*
- * setup the tail page of the log
- */
- openLog->tailPid = (lastLSN >> openLog->page2size);
- openLog->tailLSN = lastLSN;
-
- #ifdef DEBUG
- /* make sure we don't overwrite important log records */
- debugLSN.offset = openLog->tailLSN;
- debugLSN.wrapCount = openLog->wrapCount;
- debugLSN.wrapCount--;
- if(compareLSN(&debugLSN, &OldestDirtyPageLSN) >= 0) {
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- #endif DEBUG
-
- CheckpointsEnabled = TRUE; // allow checkpoints
-
- /*
- * take care of the distr trans left outstanding
- * NOTE: this also sets up openLog so that the
- * active prtion of the log is not overwritten
- * during undo
- * Hence, this must be called before calling recoverUndo
- */
- recoverPreparedTrans();
-
- /*
- * setup undo for the remaining transactions
- */
- TRPRINT(TR_LOG|TR_RECOVER, TR_LEVEL_1, ("beginning UNDO"));
- phaseTime.Start();
-
- /*
- * undo the remaining transactions
- */
- recoverUndo(lastLSN);
- phaseTime.Stop();
- phaseTime.PrintStats(sm_ErrorStream, "UndoPass");
-
- /*
- * Print recovery time statistics
- */
- recoveryTime.Stop();
- recoveryTime.PrintStats(sm_ErrorStream, "RecovTime");
-
- if (logRecordBuffer != NULL) {
- freeLogRecordBuffer(logRecordBuffer);
- logRecordBuffer = NULL;
- }
-
- #ifdef DEBUG
- /*
- * Since undo brings the system to a consistent state,
- * make sure all the volumes' bitmaps are in order
- */
- if (io_CheckAllVolumes() != esmNOERROR) {
-
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
-
- /* make sure we don't overwrite important log records */
- debugLSN.offset = openLog->tailLSN;
- debugLSN.wrapCount = openLog->wrapCount;
- debugLSN.wrapCount--;
- if(compareLSN(&debugLSN, &OldestDirtyPageLSN) >= 0) {
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- #endif DEBUG
-
- /*
- * force a checkpoint which flushes all pages and
- * wait for the checkpoint to complete
- */
- activateCheckpoint(TRUE, TRUE, TRUE);
-
- /*
- * Unmount all volumes used in recovery
- */
- if (dismountRecoveryVolumes() != esmNOERROR) {
- SM_ERROR(TYPE_FATAL, esmINTERNAL);
- }
- {
- int i;
- if( (i=io_NumOpenVolumes()) > 1) {
- fprintf(sm_ErrorStream, "PREPARED transactions were recovered; ");
- fprintf(sm_ErrorStream, "%d volumes are mounted.\n", i);
- }
- }
- }
-